package com.hzh.blog.common.utils;

/**
 *
 * @author ihavegotyou
 * Created on 2010-01-23
 * Email ihavegotyou520 AT hotmail DOT com
 * 
 * chenxu 2011-5-5 修改，主要是增加了获得本机MAC的方�?
 * 通过 ipconfig 或�? ifconfig ，另外在使用 arp获得其他机器�?
 * 的MAC 的时候ping ping完之后根据丢包率判断是否再使用arp�?
 * 获取MAC
 */

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 根据ip获取MAC地址.
 * 
 * @author ihavegotyou
 * @version 10.1.23
 * 
 * chenxu modify 2011-5-9
 */
public class GetMacFromIp {

	private static Pattern winIPConfigIPReg = Pattern.compile(": (\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$");
	private static Pattern winIPConfigMACReg = Pattern.compile(": (.{1,3}-.{1,3}-.{1,3}-.{1,3}-.{1,3}-.{1,3})$");
	private static Pattern winPingReg = Pattern.compile(".+(\\d{1,3})%.+");// ping结果正则，即丢失百分�?
	
	private static Pattern unixIFConfigIPReg = Pattern.compile(":(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})");
	private static Pattern unixIFConfigMACReg = Pattern.compile("HWaddr (.{1,3}:.{1,3}:.{1,3}:.{1,3}:.{1,3}:.{1,3}).*");
	private static Pattern unixPingReg = Pattern.compile(".+(\\d{1,3})%.+");// ping结果正则，即丢失百分�?
	
	
	private static Log logger = LogFactory.getLog(GetMacFromIp.class);

	public static String callCmd(String[] cmd) {
		String result = "";
		String line = "";
		try {
			Process proc = Runtime.getRuntime().exec(cmd);
			InputStreamReader is = new InputStreamReader(proc.getInputStream());
			BufferedReader br = new BufferedReader(is);
			while ((line = br.readLine()) != null) {
				if(StringUtils.isWhitespace(line))
					continue;
				result += line.trim()+System.getProperty("line.separator");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 
	 * @param cmd
	 *            第一个命�?
	 * @param another
	 *            第二个命�?
	 * @return 第二个命令的执行结果
	 * @deprecated waitFor 的过程会出问�?
	 */
	private static String callCmd(String[] cmd, String[] another) {
		String result = "";
		String line = "";
		try {
			Runtime rt = Runtime.getRuntime();
			Process proc = rt.exec(cmd);
			proc.waitFor(); // 已经执行完第�?��命令，准备执行第二个命令
			proc = rt.exec(another);
			InputStreamReader is = new InputStreamReader(proc.getInputStream());
			BufferedReader br = new BufferedReader(is);
			while ((line = br.readLine()) != null) {
				result += line;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 
	 * @param ip
	 *            目标ip,�?��在局域网�?
	 * @param sourceString
	 *            命令处理的结果字符串
	 * @param macSeparator
	 *            mac分隔符号
	 * @return mac地址，用上面的分隔符号表�?
	 */
	private static String filterMacAddress(final String ip,
			final String sourceString, final String macSeparator) {
		String result = "";
		String regExp = "((([0-9,A-F,a-f]{1,2}" + macSeparator
				+ "){1,5})[0-9,A-F,a-f]{1,2})";
		Pattern pattern = Pattern.compile(regExp);
		Matcher matcher = pattern.matcher(sourceString);
		while (matcher.find()) {
			result = matcher.group(1);
			if (sourceString.indexOf(ip) <= sourceString.lastIndexOf(matcher
					.group(1))) {
				break; // 如果有多个IP,只匹配本IP对应的Mac.
			}
		}

		return result;
	}

	/**
	 * 
	 * @param ip
	 *            目标ip
	 * @return Mac Address
	 * 
	 */
	public static String getMacInWindows(final String ip) {
		String resultMAC = null;

		// 执行ipconfig 获得本地 地址信息
		String[] ipconfig = { "cmd", "/c", "ipconfig/all" };
		resultMAC = callCmd(ipconfig);
		Matcher matcherIP = winIPConfigIPReg.matcher(resultMAC);
		List<String> localIP = new ArrayList<String>();
		String localMAC = null;
		while (matcherIP.find()) {
			String matchResult = matcherIP.group(1);
			localIP.add(matchResult);
		}
		//获得本地的mac
		Matcher matcherMAC = winIPConfigMACReg.matcher(resultMAC);
		if (matcherMAC.find()) {
			localMAC = matcherMAC.group(1);
		}
		// 如�?是本地IP直接返回
		if (localIP.contains(ip)) {
			return localMAC;
		}
		// 执行ipconfig 获得本地 地址信息

		// 如果符合下面的条件也返回本地 MAC
		if (ip.toLowerCase().equals("localhost") || ip.equals("127.0.0.1")) {
			return localMAC;
		}

		// 先进行一次ping好保证可以获得这个ip 的mac
		String[] ping = { "cmd", "/c", "ping " + ip +" -n 2"};//只发送两个ping�?
		String cmdResult = callCmd(ping);
		Matcher matcherPing = winPingReg.matcher(cmdResult);
		int percent = 0;// ping的丢失率，如果小�?100 说明是ping通的
		if (matcherPing.find()) {
			String percentStr = matcherPing.group(1);
			percent = Integer.parseInt(percentStr);
		}
		if (percent < 100) {// 小于 0 说明有ping同的包，使用arp获得这个ip的MAC
			String[] arp = { "cmd", "/c", "arp -a" };
			cmdResult = callCmd(arp);
			resultMAC = filterMacAddress(ip, cmdResult, "-");
		} else {
			resultMAC = "";
			logger.warn("ping ip["+ip+"] use 2 package can't arrive, set "+ip+"'s mac blank ");
		}

		return resultMAC;
	}

	/**
	 * 根据IP地址返回 MAC
	 * 
	 * @param ipAddress
	 * @return MAC 地址
	 */
	public static String getMac(String ipAddress) {
		String macAddress = null;
		if(StringUtils.isBlank(ipAddress)) {
			logger.warn("ipAddress isBlank ["+ipAddress+"] can't get macAddress!");
			return macAddress; 
		}
		String osName = SystemTool.getOSName();

		if (osName != null && osName.startsWith("windows")) {
			macAddress = getMacInWindows(ipAddress);
		} else {
			macAddress = getMacInLinux(ipAddress);
		}
		return macAddress;
	}

	/**
	 * 
	 * @param ip
	 *            目标ip
	 * @return Mac Address
	 * 
	 */
	public static String getMacInLinux(final String ip) {


		String resultMAC = null;

		// 执行ipconfig 获得本地 地址信息
		String[] ifconfig = { "/bin/sh","-c", "ifconfig" };
		resultMAC = callCmd(ifconfig);
		Matcher matcherIP = unixIFConfigIPReg.matcher(resultMAC);
		List<String> localIP = new ArrayList<String>();
		String localMAC = null;
		while (matcherIP.find()) {
			String matchResult = matcherIP.group(1);
			localIP.add(matchResult);
		}
		//获得本地的mac
		Matcher matcherMAC = unixIFConfigMACReg.matcher(resultMAC);
		if (matcherMAC.find()) {
			localMAC = matcherMAC.group(1);
		}
		// 如�?是本地IP直接返回
		if (localIP.contains(ip)) {
			return localMAC;
		}
		// 执行ipconfig 获得本地 地址信息

		// 如果符合下面的条件也返回本地 MAC
		if (ip.toLowerCase().equals("localhost") || ip.equals("127.0.0.1")) {
			return localMAC;
		}

		// 先进行一次ping好保证可以获得这个ip 的mac
		String[] ping = { "/bin/sh", "-c", "ping " +  ip + " -c 2" };
		String cmdResult = callCmd(ping);
		Matcher matcherPing = unixPingReg.matcher(cmdResult);
		int percent = 0;// ping的丢失率，如果小�?100 说明是ping通的
		if (matcherPing.find()) {
			String percentStr = matcherPing.group(1);
			percent = Integer.parseInt(percentStr);
		}
		if (percent < 100) {// 小于 0 说明有ping同的包，使用arp获得这个ip的MAC
			String[] arp = { "/bin/sh", "-c", "arp -a" };
			cmdResult = callCmd(arp);
			resultMAC = filterMacAddress(ip, cmdResult, ":");
		} else {
			resultMAC = "";
			logger.warn("ping ip["+ip+"] use 2 package can't arrive, set "+ip+"'s mac blank ");
		}

		return resultMAC;
	}

	/**
	 * 测试
	 */
	public static void main(String[] args) {

		String fileSeparator = System.getProperty("file.separator"); // 根据文件分隔符号区分平台
		if (fileSeparator.equals("/")) {
			System.out.println(getMacInLinux("192.168.6.23"));
		} else if (fileSeparator.equals("\\")) {
			System.out.println(getMacInWindows("192.53.0.156")); // nicrosoft喜欢对着�?
			// System.out.println(getMacInWindows("127.0.0.1"));
		}

		Matcher matcher = winIPConfigIPReg
				.matcher("IP Address. . . . . . . . . . . . : 192.53.0.23");
		while (matcher.find()) {
			String group = matcher.group(1);
			System.out.println("ip" + group);
		}

		Matcher m = winIPConfigMACReg
				.matcher("Realtek PCIe GBE Family ControllerPhysical Address. . . . . . . . . : 1C-6F-65-98-69-1CDhcp Enabled");
		while (m.find()) {
			String mac = m.group(1);
			System.out.println("mac" + mac);
		}
	}

}
